#!/usr/bin/env node

/**
 * 爬虫稳定性测试工具
 * 循环执行同一个任务，测试稳定性和成功率
 * 
 * 用法：
 *   node stress-test.js                          # 无限循环执行
 *   node stress-test.js --count 10               # 执行10次
 *   node stress-test.js --task amazon-de         # 指定任务
 *   node stress-test.js --delay 5000             # 每次执行间隔5秒
 *   node stress-test.js --count 50 --delay 3000  # 组合使用
 */

const fs = require('fs');
const path = require('path');
const main = require('./run');

// 解析命令行参数
function parseArgs() {
    const args = process.argv.slice(2);
    const options = {
        count: null,           // null 表示无限循环
        task: null,            // 指定任务名称
        delay: 2000,           // 每次执行间隔（毫秒）
        stopOnError: false,    // 是否在出错时停止
        saveLog: true          // 是否保存日志
    };

    for (let i = 0; i < args.length; i++) {
        const arg = args[i];

        if (arg === '--count' || arg === '-c') {
            options.count = parseInt(args[++i]) || null;
        } else if (arg === '--task' || arg === '-t') {
            options.task = args[++i];
        } else if (arg === '--delay' || arg === '-d') {
            options.delay = parseInt(args[++i]) || 2000;
        } else if (arg === '--stop-on-error' || arg === '-s') {
            options.stopOnError = true;
        } else if (arg === '--no-log') {
            options.saveLog = false;
        } else if (arg === '--help' || arg === '-h') {
            console.log(`
爬虫稳定性测试工具

用法：
  node stress-test.js [选项]

选项：
  -c, --count <次数>       执行次数（默认：无限循环）
  -t, --task <任务名>      指定要测试的任务（默认：所有任务）
  -d, --delay <毫秒>       每次执行间隔时间（默认：2000ms）
  -s, --stop-on-error      遇到错误时停止测试
  --no-log                 不保存测试日志
  -h, --help               显示帮助信息

示例：
  node stress-test.js                              # 无限循环测试所有任务
  node stress-test.js -c 10                        # 测试10次
  node stress-test.js -t amazon-de -c 50           # 测试亚马逊德国任务50次
  node stress-test.js -c 100 -d 5000               # 测试100次，间隔5秒
  node stress-test.js -t amazon-de -c 20 -s        # 测试20次，出错即停止

提示：
  - 按 Ctrl+C 可随时停止测试
  - 测试结果会自动保存到 stress-test-results/ 目录
  - 使用 --no-log 可以禁用日志保存（用于快速测试）
            `);
            process.exit(0);
        }
    }

    return options;
}

// 统计信息
class TestStatistics {
    constructor() {
        this.totalRuns = 0;
        this.successRuns = 0;
        this.failedRuns = 0;
        this.errors = [];
        this.runTimes = [];
        this.startTime = Date.now();
    }

    recordRun(success, duration, error = null) {
        this.totalRuns++;
        if (success) {
            this.successRuns++;
        } else {
            this.failedRuns++;
            if (error) {
                this.errors.push({
                    runNumber: this.totalRuns,
                    error: error.message || String(error),
                    timestamp: new Date().toISOString()
                });
            }
        }
        this.runTimes.push(duration);
    }

    getSuccessRate() {
        return this.totalRuns > 0 
            ? ((this.successRuns / this.totalRuns) * 100).toFixed(2) 
            : 0;
    }

    getAverageTime() {
        if (this.runTimes.length === 0) return 0;
        const sum = this.runTimes.reduce((a, b) => a + b, 0);
        return (sum / this.runTimes.length / 1000).toFixed(2); // 转换为秒
    }

    getMinTime() {
        return this.runTimes.length > 0 
            ? (Math.min(...this.runTimes) / 1000).toFixed(2) 
            : 0;
    }

    getMaxTime() {
        return this.runTimes.length > 0 
            ? (Math.max(...this.runTimes) / 1000).toFixed(2) 
            : 0;
    }

    getTotalTime() {
        return ((Date.now() - this.startTime) / 1000).toFixed(2);
    }

    printSummary() {
        console.log('\n' + '='.repeat(80));
        console.log('📊 测试统计摘要');
        console.log('='.repeat(80));
        console.log(`总执行次数: ${this.totalRuns}`);
        console.log(`成功次数:   ${this.successRuns} ✅`);
        console.log(`失败次数:   ${this.failedRuns} ❌`);
        console.log(`成功率:     ${this.getSuccessRate()}%`);
        console.log(`总耗时:     ${this.getTotalTime()} 秒`);
        console.log(`平均耗时:   ${this.getAverageTime()} 秒/次`);
        console.log(`最快耗时:   ${this.getMinTime()} 秒`);
        console.log(`最慢耗时:   ${this.getMaxTime()} 秒`);
        
        if (this.errors.length > 0) {
            console.log('\n最近的错误:');
            this.errors.slice(-5).forEach(err => {
                console.log(`  [Run ${err.runNumber}] ${err.error}`);
            });
        }
        console.log('='.repeat(80) + '\n');
    }

    saveToFile(options) {
        try {
            const resultsDir = path.join(__dirname, 'stress-test-results');
            if (!fs.existsSync(resultsDir)) {
                fs.mkdirSync(resultsDir, { recursive: true });
            }

            const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
            const filename = `test_${timestamp}.json`;
            const filepath = path.join(resultsDir, filename);

            const data = {
                summary: {
                    totalRuns: this.totalRuns,
                    successRuns: this.successRuns,
                    failedRuns: this.failedRuns,
                    successRate: this.getSuccessRate(),
                    totalTime: this.getTotalTime(),
                    averageTime: this.getAverageTime(),
                    minTime: this.getMinTime(),
                    maxTime: this.getMaxTime()
                },
                options: options,
                errors: this.errors,
                runTimes: this.runTimes,
                timestamp: new Date().toISOString()
            };

            fs.writeFileSync(filepath, JSON.stringify(data, null, 2), 'utf-8');
            console.log(`\n💾 测试结果已保存到: ${filepath}`);
        } catch (error) {
            console.error(`❌ 保存测试结果失败: ${error.message}`);
        }
    }
}

// 主测试函数
async function runStressTest() {
    const options = parseArgs();
    const stats = new TestStatistics();

    console.log('========================================');
    console.log('    爬虫稳定性测试工具');
    console.log('========================================\n');

    console.log('测试配置:');
    console.log(`  执行次数: ${options.count || '∞ (无限循环)'}`);
    console.log(`  目标任务: ${options.task || '所有任务'}`);
    console.log(`  执行间隔: ${options.delay}ms`);
    console.log(`  出错停止: ${options.stopOnError ? '是' : '否'}`);
    console.log(`  保存日志: ${options.saveLog ? '是' : '否'}`);
    console.log('\n提示: 按 Ctrl+C 可随时停止测试\n');

    // 设置 Ctrl+C 处理
    let isRunning = true;
    process.on('SIGINT', () => {
        console.log('\n\n⚠️  收到中断信号，正在停止测试...\n');
        isRunning = false;
    });

    // 构建 process.argv 参数
    const baseArgs = process.argv.slice(0, 2);
    const taskArgs = options.task ? ['--task', options.task] : [];

    let runNumber = 0;

    while (isRunning && (options.count === null || runNumber < options.count)) {
        runNumber++;
        
        console.log('\n' + '━'.repeat(80));
        console.log(`🚀 第 ${runNumber}${options.count ? `/${options.count}` : ''} 次执行`);
        console.log('━'.repeat(80) + '\n');

        const startTime = Date.now();
        let success = false;
        let error = null;

        try {
            // 临时替换 process.argv
            const originalArgv = process.argv;
            process.argv = [...baseArgs, ...taskArgs];

            // 执行爬虫任务
            await main();
            
            // 恢复 process.argv
            process.argv = originalArgv;

            success = true;
            console.log(`\n✅ 第 ${runNumber} 次执行成功`);

        } catch (err) {
            error = err;
            success = false;
            console.error(`\n❌ 第 ${runNumber} 次执行失败:`, err.message);

            if (options.stopOnError) {
                console.log('\n⚠️  检测到错误，停止测试（--stop-on-error）\n');
                isRunning = false;
            }
        }

        const duration = Date.now() - startTime;
        stats.recordRun(success, duration, error);

        // 打印当前统计
        console.log(`\n📊 当前统计: ${stats.successRuns}✅ / ${stats.failedRuns}❌ (成功率: ${stats.getSuccessRate()}%)`);

        // 如果还要继续执行，等待间隔时间
        if (isRunning && (options.count === null || runNumber < options.count)) {
            console.log(`\n⏸️  等待 ${options.delay}ms 后继续...\n`);
            await new Promise(resolve => setTimeout(resolve, options.delay));
        }
    }

    // 打印最终统计
    stats.printSummary();

    // 保存结果
    if (options.saveLog) {
        stats.saveToFile(options);
    }

    console.log('🎉 测试完成！\n');
}

// 运行测试
if (require.main === module) {
    runStressTest().catch(error => {
        console.error('❌ 测试过程中出现致命错误:', error);
        process.exit(1);
    });
}

module.exports = runStressTest;


